%%% -------------------------------------------------------------------
%%% Author  : maciek
%%% Description :
%%%
%%% Created : 16-04-2011
%%% -------------------------------------------------------------------
-module(src_call_id_generator).

-behaviour(gen_server).
%% --------------------------------------------------------------------
%% Include files
%% --------------------------------------------------------------------

%% --------------------------------------------------------------------
%% External exports
-export([start_link/0,allocsrccallid/0,disallocsrccallid/1,terminate/0,get_allocated_count/0]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(srcidgenstate, {allocatedids=[]}).

%% ====================================================================
%% External functions
%% ====================================================================
start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []),
	ok.
allocsrccallid() ->
    gen_server:call(?MODULE, allocsrccallid).
terminate() ->
	gen_server:call(?MODULE,terminate).
get_allocated_count() ->
	gen_server:call(?MODULE, get_allocated_count).



disallocsrccallid(Id) ->
    gen_server:call(?MODULE, {disalloccallid,Id}).

%% ====================================================================
%% Server functions
%% ====================================================================

%% --------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State}          |
%%          {ok, State, Timeout} |
%%          ignore               |
%%          {stop, Reason}
%% --------------------------------------------------------------------
init([]) ->
	io:format("Starting new src call id generator ~n"),
    {ok, #srcidgenstate{}}.

%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State}          |
%%          {reply, Reply, State, Timeout} |
%%          {noreply, State}               |
%%          {noreply, State, Timeout}      |
%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call(allocsrccallid, _From, #srcidgenstate{allocatedids=Alloc}) ->
    Rnd = generate_random_nbr(2#111111111111111, Alloc),
	NewAlloc = [Rnd|Alloc],	
    {reply, Rnd, #srcidgenstate{allocatedids=NewAlloc}};


handle_call({disalloccallid, Id}, _From, #srcidgenstate{allocatedids=Alloc}) ->
    Reply = ok,
	NewAlloc = lists:delete(Id, Alloc),
    {reply, Reply, #srcidgenstate{allocatedids=NewAlloc}};


handle_call(terminate, _From, State) ->
 
   {stop,normal,State};


handle_call(get_allocated_count,_From,#srcidgenstate{allocatedids=Alloc}) ->
  {reply,length(Alloc),#srcidgenstate{allocatedids=Alloc}}.
%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast(_Msg, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info(_Info, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(Reason, State) ->
    ok.

%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(OldVsn, State, Extra) ->
    {ok, State}.

%% --------------------------------------------------------------------
%%% Internal functions
%% --------------------------------------------------------------------
generate_random_nbr(Max,RestrictedList) ->
	Rnd=random:uniform(Max),
	Restricted=lists:member(Rnd, RestrictedList),
	if 
		not Restricted ->
		   Rnd;
	   true -> generate_random_nbr(Max,RestrictedList)
	end.
